package org.tea.inventory.utils;

/**
 * @author hanzy
 * @description
 * @date 2023年07月12日 15:08
 */

import cn.hutool.cron.pattern.CronPatternUtil;
import com.cronutils.model.Cron;
import com.cronutils.model.definition.CronDefinition;
import com.cronutils.model.definition.CronDefinitionBuilder;
import com.cronutils.model.time.ExecutionTime;
import com.cronutils.parser.CronParser;

import static com.cronutils.model.CronType.QUARTZ;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.quartz.CronExpression;

import java.security.KeyPair;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.Optional;

/**
 * @author longwei
 * @Description 日期时间转Cron表达式
 * @date 2022/11/4 18:17
 */
public class DateTimeToCronUtils {

    /**
     * 每年format格式
     */
    public static final String YEAR = "ss mm HH dd MM ? yyyy";

    /**
     * 每周format格式
     */
    public static final String MONDAY = "ss mm HH ? * 1";
    public static final String TUESDAY = "ss mm HH ? * 2";
    public static final String WEDNESDAY = "ss mm HH ? * 3";
    public static final String THURSDAY = "ss mm HH ? * 4";
    public static final String FRIDAY = "ss mm HH ? * 5";
    public static final String SATURDAY = "ss mm HH ? * 6";
    public static final String SUNDAY = "ss mm HH ? * 7";

    /**
     * 每天format格式
     */
    public static final String EVERYDAY = "ss mm HH * * ?";

    /**
     * 间隔-每天format格式
     */
    public static final String INTERVAL_DAY = "0 0 0 1/param * ? ";

    /**
     * 间隔-每小时format格式
     */
    public static final String INTERVAL_HOUR = "0 0 0/param * * ?";

    /**
     * 间隔-每分钟format格式
     */
    public static final String INTERVAL_MINUTE = "0 0/param * * * ? ";

    /**
     * LocalDateTime格式化为String
     *
     * @param date       LocalDateTime
     * @param dateFormat format格式
     * @return String
     * @author longwei
     */
    public static String formatDateByPattern(LocalDateTime date, String dateFormat) {
        return DateUtil.format(date, dateFormat);
    }

    /**
     * date格式化为String
     *
     * @param date       date
     * @param dateFormat format格式
     * @return String
     * @author longwei
     */
    public static String formatDateByPattern(Date date, String dateFormat) {
        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    /**
     * 时间转换Cron表达式
     *
     * @param date       date
     * @param dateFormat format格式
     * @return Cron表达式
     * @author longwei
     */
    public static String getCron(Date date, String dateFormat) {
        return formatDateByPattern(date, dateFormat);
    }

    /**
     * 时间转换Cron表达式
     *
     * @param date       date
     * @param dateFormat format格式
     * @return Cron表达式
     * @author longwei
     */
    public static String getCron(LocalDateTime date, String dateFormat) {
        return formatDateByPattern(date, dateFormat);
    }

    /**
     * 间隔天转换Cron表达式
     *
     * @param param 天
     * @return Cron表达式
     * @author longwei
     */
    public static String getIntervalDayCron(String param) {
        return INTERVAL_DAY.replace("param", param);
    }

    /**
     * 间隔小时转换Cron表达式
     *
     * @param param 小时
     * @return Cron表达式
     * @author longwei
     */
    public static String getIntervalHourCron(String param) {
        return INTERVAL_HOUR.replace("param", param);
    }

    /**
     * 间隔分钟转换Cron表达式
     *
     * @param param 分钟
     * @return Cron表达式
     * @author longwei
     */
    public static String getIntervalMinuteCron(String param) {
        return INTERVAL_MINUTE.replace("param", param);
    }


    public static Date cron2Date(String cron) {
        // 转换 new Date 是为了给最近一次执行时间一个初始时间，这里给当前时间
        CronExpression cronExpression = null;
        try {
            cronExpression = new CronExpression(cron);
            if (cronExpression.getNextValidTimeAfter(new Date()) != null) {
                return cronExpression.getNextValidTimeAfter(new Date());
            } else {
                String year = StrUtil.subSufByLength(cron,4);
                if (year.length() == 4) {
                    return cronExpression.getNextValidTimeAfter(DateTime.of(year, DatePattern.NORM_YEAR_PATTERN));
                }

            }

        } catch (ParseException e) {
            return null;
        }
        return null;
    }


    /**
     * 验证cron表达式是否正确
     *
     * @param cronExpression
     * @return
     */
    public static boolean isValid(String cronExpression) {
        return CronExpression.isValidExpression(cronExpression);
    }

    private static final CronDefinition CRON_DEFINITION = CronDefinitionBuilder.instanceDefinitionFor(QUARTZ);

    public static LocalDateTime lastExecution(String expression) {
        CronParser parser = new CronParser(CRON_DEFINITION);
        Cron quartzCron = parser.parse(expression);
        ZonedDateTime now = ZonedDateTime.now();
        ExecutionTime executionTime = ExecutionTime.forCron(quartzCron);
        Optional<ZonedDateTime> zonedDateTimeOptional = executionTime.lastExecution(now);
        if (zonedDateTimeOptional.isPresent()) {
            ZonedDateTime zonedDateTime = zonedDateTimeOptional.get();
            return zonedDateTime.toLocalDateTime();
        }
        return null;
    }

    public static LocalDateTime nextExecution(String expression) {
        CronParser parser = new CronParser(CRON_DEFINITION);
        Cron quartzCron = parser.parse(expression);
        ZonedDateTime now = ZonedDateTime.now();
        ExecutionTime executionTime = ExecutionTime.forCron(quartzCron);
        Optional<ZonedDateTime> zonedDateTimeOptional = executionTime.nextExecution(now);
        if (zonedDateTimeOptional.isPresent()) {
            ZonedDateTime zonedDateTime = zonedDateTimeOptional.get();
            return zonedDateTime.toLocalDateTime();
        }
        return null;
    }


    public static void main(String[] args) {
        LocalDateTime date = lastExecution("0 0 0 1 1 ? 2024");
        int i=0;
    }

}
